home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 001a / rzsz1291.zip / RZ.C < prev    next >
C/C++ Source or Header  |  1991-10-30  |  28KB  |  1,289 lines

  1. #define VERSION "3.17 10-30-91"
  2. #define PUBDIR "/usr/spool/uucppublic"
  3.  
  4. /*
  5.  *
  6.  * rz.c By Chuck Forsberg
  7.  *    Copyright 1991 Omen Technology Inc All Rights Reserved
  8.  *
  9.  * A program for Unix to receive files and commands from computers running
  10.  *  Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM.
  11.  *  rz uses Unix buffered input to reduce wasted CPU time.
  12.  *
  13.  *
  14.  *    This version implements numerous enhancements including ZMODEM
  15.  *    Run Length Encoding and variable length headers.  These
  16.  *    features were not funded by the original Telenet development
  17.  *    contract.
  18.  * 
  19.  * This software may be freely used for non commercial and
  20.  * educational (didactic only) purposes.  This software may also
  21.  * be freely used to support file transfer operations to or from
  22.  * licensed Omen Technology products.  Any programs which use
  23.  * part or all of this software must be provided in source form
  24.  * with this notice intact except by written permission from Omen
  25.  * Technology Incorporated.
  26.  * 
  27.  * Use of this software for commercial or administrative purposes
  28.  * except when exclusively limited to interfacing Omen Technology
  29.  * products requires a per port license payment of $20.00 US per
  30.  * port (less in quantity).  Use of this code by inclusion,
  31.  * decompilation, reverse engineering or any other means
  32.  * constitutes agreement to these conditions and acceptance of
  33.  * liability to license the materials and payment of reasonable
  34.  * legal costs necessary to enforce this license agreement.
  35.  *
  36.  *
  37.  *        Omen Technology Inc        FAX: 503-621-3745
  38.  *        Post Office Box 4681
  39.  *        Portland OR 97208
  40.  *
  41.  *    This code is made available in the hope it will be useful,
  42.  *    BUT WITHOUT ANY WARRANTY OF ANY KIND OR LIABILITY FOR ANY
  43.  *    DAMAGES OF ANY KIND.
  44.  *
  45.  *
  46.  *
  47.  * Iff the program is invoked by rzCOMMAND, output is piped to 
  48.  * "COMMAND filename"  (Unix only)
  49.  *
  50.  *  Alarm signal handling changed to work with 4.2 BSD 7-15-84 CAF 
  51.  *
  52.  *  SEGMENTS=n added 2-21-88 as a model for CP/M programs
  53.  *    for CP/M-80 systems that cannot overlap modem and disk I/O.
  54.  *
  55.  *  -DMD may be added to compiler command line to compile in
  56.  *    Directory-creating routines from Public Domain TAR by John Gilmore
  57.  *
  58.  *  HOWMANY may be tuned for best performance
  59.  *
  60.  *  USG UNIX (3.0) ioctl conventions courtesy  Jeff Martin
  61.  */
  62.  
  63.  
  64.  
  65. #define LOGFILE "/tmp/rzlog"
  66. #include <stdio.h>
  67. #include <signal.h>
  68. #include <ctype.h>
  69. #include <errno.h>
  70. extern int errno;
  71. FILE *popen();
  72.  
  73. #define OK 0
  74. #define FALSE 0
  75. #define TRUE 1
  76. #define ERROR (-1)
  77.  
  78. /*
  79.  * Max value for HOWMANY is 255.
  80.  *   A larger value reduces system overhead but may evoke kernel bugs.
  81.  *   133 corresponds to an XMODEM/CRC sector
  82.  */
  83. #ifndef HOWMANY
  84. #define HOWMANY 96
  85. #endif
  86.  
  87. /* Ward Christensen / CP/M parameters - Don't change these! */
  88. #define ENQ 005
  89. #define CAN ('X'&037)
  90. #define XOFF ('s'&037)
  91. #define XON ('q'&037)
  92. #define SOH 1
  93. #define STX 2
  94. #define EOT 4
  95. #define ACK 6
  96. #define NAK 025
  97. #define CPMEOF 032
  98. #define WANTCRC 0103    /* send C not NAK to get crc not checksum */
  99. #define TIMEOUT (-2)
  100. #define RCDO (-3)
  101. #define GCOUNT (-4)
  102. #define ERRORMAX 5
  103. #define RETRYMAX 5
  104. #define WCEOT (-10)
  105. #define PATHLEN 257    /* ready for 4.2 bsd ? */
  106. #define UNIXFILE 0xF000    /* The S_IFMT file mask bit for stat */
  107.  
  108. int Zmodem=0;        /* ZMODEM protocol requested */
  109. int Nozmodem = 0;    /* If invoked as "rb" */
  110. unsigned Baudrate = 2400;
  111. unsigned Effbaud = 2400;
  112. #include "rbsb.c"    /* most of the system dependent stuff here */
  113. #include "crctab.c"
  114. char endmsg[90] = {0};    /* Possible message to display on exit */
  115.  
  116. char *substr();
  117. FILE *fout;
  118.  
  119. /*
  120.  * Routine to calculate the free bytes on the current file system
  121.  *  ~0 means many free bytes (unknown)
  122.  */
  123. long getfree()
  124. {
  125.     return(~0L);    /* many free bytes ... */
  126. }
  127.  
  128. int Lastrx;
  129. long rxbytes;
  130. int Crcflg;
  131. int Firstsec;
  132. int Eofseen;        /* indicates cpm eof (^Z) has been received */
  133. int errors;
  134. int Restricted=0;    /* restricted; no /.. or ../ in filenames */
  135.  
  136. #define DEFBYTL 2000000000L    /* default rx file size */
  137. long Bytesleft;        /* number of bytes of incoming file left */
  138. long Modtime;        /* Unix style mod time for incoming file */
  139. int Filemode;        /* Unix style mode for incoming file */
  140. long Totalleft;
  141. long Filesleft;
  142. char Pathname[PATHLEN];
  143. char *Progname;        /* the name by which we were called */
  144.  
  145. int Batch=0;
  146. int Topipe=0;
  147. int Thisbinary;        /* current file is to be received in bin mode */
  148. int Rxbinary=FALSE;    /* receive all files in bin mode */
  149. int Rxascii=FALSE;    /* receive files in ascii (translate) mode */
  150. int Blklen;        /* record length of received packets */
  151.  
  152. #ifdef SEGMENTS
  153. int chinseg = 0;    /* Number of characters received in this data seg */
  154. char secbuf[1+(SEGMENTS+1)*1024];
  155. #else
  156. char secbuf[1025];
  157. #endif
  158.  
  159.  
  160. time_t timep[2];
  161. char Lzmanag;        /* Local file management request */
  162. char Lzconv;        /* Local ZMODEM file conversion request */
  163. char zconv;        /* ZMODEM file conversion request */
  164. char zmanag;        /* ZMODEM file management request */
  165. char ztrans;        /* ZMODEM file transport request */
  166. int Zctlesc;        /* Encode control characters */
  167. int Zrwindow = 1400;    /* RX window size (controls garbage count) */
  168.  
  169. #include "zm.c"
  170.  
  171. #include "zmr.c"
  172.  
  173. int tryzhdrtype=ZRINIT;    /* Header type to send corresponding to Last rx close */
  174.  
  175.  
  176. /* called by signal interrupt or terminate to clean things up */
  177. bibi(n)
  178. {
  179.     if (Zmodem)
  180.         zmputs(Attn);
  181.     canit(); mode(0);
  182.     fprintf(stderr, "rz: caught signal %d; exiting", n);
  183.     exit(3);
  184. }
  185.  
  186. main(argc, argv)
  187. char *argv[];
  188. {
  189.     register char *cp;
  190.     register npats;
  191.     char *virgin, **patts;
  192.     char *getenv();
  193.     int exitcode = 0;
  194.  
  195.     Rxtimeout = 100;
  196.     setbuf(stderr, NULL);
  197.     if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh")))
  198.         Restricted=TRUE;
  199.  
  200.     chkinvok(virgin=argv[0]);    /* if called as [-]rzCOMMAND set flag */
  201.     inittty();
  202.     npats = 0;
  203.     while (--argc) {
  204.         cp = *++argv;
  205.         if (*cp == '-') {
  206.             while( *++cp) {
  207.                 switch(*cp) {
  208.                 case '\\':
  209.                      cp[1] = toupper(cp[1]);  continue;
  210.                 case 'a':
  211.                     if (!Batch || Nozmodem)
  212.                         Rxascii=TRUE;
  213.                     else
  214.                         usage();
  215.                     break;
  216.                 case 't':
  217.                     if (--argc < 1) {
  218.                         usage();
  219.                     }
  220.                     Rxtimeout = atoi(*++argv);
  221.                     if (Rxtimeout<10 || Rxtimeout>1000)
  222.                         usage();
  223.                     break;
  224.                 case 'w':
  225.                     if (--argc < 1) {
  226.                         usage();
  227.                     }
  228.                     Zrwindow = atoi(*++argv);
  229.                     break;
  230.                 case 'v':
  231.                     ++Verbose; break;
  232.                 default:
  233.                     usage();
  234.                 }
  235.             }
  236.         }
  237.         else if ( !npats && argc>0) {
  238.             if (argv[0][0]) {
  239.                 npats=argc;
  240.                 patts=argv;
  241.             }
  242.         }
  243.     }
  244.     if (npats > 1)
  245.         usage();
  246.     if (Batch && npats)
  247.         usage();
  248.     if (Verbose) {
  249.         if (freopen(LOGFILE, "a", stderr)==NULL) {
  250.             printf("Can't open log file %s\n",LOGFILE);
  251.             exit(2);
  252.         }
  253.         setbuf(stderr, NULL);
  254.         fprintf(stderr, "argv[0]=%s Progname=%s\n", virgin, Progname);
  255.     }
  256.     vfile("%s %s for %s\n", Progname, VERSION, OS);
  257.     mode(1);
  258.     if (signal(SIGINT, bibi) == SIG_IGN) {
  259.         signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
  260.     }
  261.     else {
  262.         signal(SIGINT, bibi); signal(SIGKILL, bibi);
  263.     }
  264.     signal(SIGTERM, bibi);
  265.     if (wcreceive(npats, patts)==ERROR) {
  266.         exitcode=1;
  267.         canit();
  268.     }
  269.     mode(0);
  270.     if (exitcode && !Zmodem)    /* bellow again with all thy might. */
  271.         canit();
  272.     if (endmsg[0])
  273.         printf("  %s: %s\r\n", Progname, endmsg);
  274.     printf("%s %s finished.\r\n", Progname, VERSION);
  275.     fflush(stdout);
  276.     exit(exitcode != 0);
  277. }
  278.  
  279.  
  280. usage()
  281. {
  282.     fprintf(stderr,
  283.     "Receive Files and Commands with ZMODEM/YMODEM/XMODEM Protocol\n\n");
  284.     fprintf(stderr,"%s %s for %s by Chuck Forsberg, Omen Technology INC\n",
  285.       Progname, VERSION, OS);
  286.     fprintf(stderr, "\t\t\042The High Reliability Software\042\n\n");
  287.     fprintf(stderr,"Usage:    rz [-v]        (ZMODEM)\n");
  288.     fprintf(stderr,"or    rb [-av]    (YMODEM)\n");
  289.     fprintf(stderr,"or    rc [-av] file    (XMODEM-CRC)\n");
  290.     fprintf(stderr,"or    rx [-av] file    (XMODEM)\n\n");
  291.     fprintf(stderr,
  292.     "\nSee rz.doc for option descriptions and licensing information.\n\n");
  293.     fprintf(stderr,
  294. "Supports incoming ZMODEM binary (-b), ASCII CR/LF>NL (-a), newer(-n),\n\
  295.     newer+longer(-N), protect (-p), Crash Recovery (-r),\n\
  296. clobber (-y), match+clobber (-Y), compression (-Z), and append (-+).\n\n");
  297.     fprintf(stderr,"\tCopyright 1991 Omen Technology INC All Rights Reserved\n");
  298.     exit(2);
  299. }
  300.  
  301. /*
  302.  * Let's receive something already.
  303.  */
  304.  
  305. char *rbmsg = "%s ready. Type \"%s file ...\" to your modem program\n\r";
  306.  
  307. wcreceive(argc, argp)
  308. char **argp;
  309. {
  310.     register c;
  311.  
  312.     if (Batch || argc==0) {
  313.         Crcflg=1;
  314.         fprintf(stderr, rbmsg, Progname, Nozmodem?"sb":"sz");
  315.         if (c=tryz()) {
  316.             if (c == ZCOMPL)
  317.                 return OK;
  318.             if (c == ERROR)
  319.                 goto fubar;
  320.             c = rzfiles();
  321.             if (c)
  322.                 goto fubar;
  323.         } else {
  324.             for (;;) {
  325.                 if (wcrxpn(secbuf)== ERROR)
  326.                     goto fubar;
  327.                 if (secbuf[0]==0)
  328.                     return OK;
  329.                 if (procheader(secbuf) == ERROR)
  330.                     goto fubar;
  331.                 if (wcrx()==ERROR)
  332.                     goto fubar;
  333.             }
  334.         }
  335.     } else {
  336.         Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  337.  
  338.         procheader(""); strcpy(Pathname, *argp); checkpath(Pathname);
  339.         fprintf(stderr, "\nrz: ready to receive %s\r\n", Pathname);
  340.         if ((fout=fopen(Pathname, "w")) == NULL)
  341.             return ERROR;
  342.         if (wcrx()==ERROR)
  343.             goto fubar;
  344.     }
  345.     return OK;
  346. fubar:
  347.     canit();
  348.     if (Topipe && fout) {
  349.         pclose(fout);  return ERROR;
  350.     }
  351.     Modtime = 1;
  352.     if (fout)
  353.         fclose(fout);
  354.     if (Restricted) {
  355.         unlink(Pathname);
  356.         fprintf(stderr, "\r\nrz: %s removed.\r\n", Pathname);
  357.     }
  358.     return ERROR;
  359. }
  360.  
  361.  
  362. /*
  363.  * Fetch a pathname from the other end as a C ctyle ASCIZ string.
  364.  * Length is indeterminate as long as less than Blklen
  365.  * A null string represents no more files (YMODEM)
  366.  */
  367. wcrxpn(rpn)
  368. char *rpn;    /* receive a pathname */
  369. {
  370.     register c;
  371.  
  372.     purgeline();
  373.  
  374. et_tu:
  375.     Firstsec=TRUE;  Eofseen=FALSE;
  376.     sendline(Crcflg?WANTCRC:NAK);
  377.     Lleft=0;    /* Do read next time ... */
  378.     while ((c = wcgetsec(rpn, 100)) != 0) {
  379.         if (c == WCEOT) {
  380.             zperr( "Pathname fetch returned %d", c);
  381.             sendline(ACK);
  382.             Lleft=0;    /* Do read next time ... */
  383.             readline(1);
  384.             goto et_tu;
  385.         }
  386.         return ERROR;
  387.     }
  388.     sendline(ACK);
  389.     return OK;
  390. }
  391.  
  392. /*
  393.  * Adapted from CMODEM13.C, written by
  394.  * Jack M. Wierda and Roderick W. Hart
  395.  */
  396.  
  397. wcrx()
  398. {
  399.     register int sectnum, sectcurr;
  400.     register char sendchar;
  401.     register char *p;
  402.     int cblklen;            /* bytes to dump this block */
  403.  
  404.     Firstsec=TRUE;sectnum=0; Eofseen=FALSE;
  405.     sendchar=Crcflg?WANTCRC:NAK;
  406.  
  407.     for (;;) {
  408.         sendline(sendchar);    /* send it now, we're ready! */
  409.         Lleft=0;    /* Do read next time ... */
  410.         sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130);
  411.         report(sectcurr);
  412.         if (sectcurr==(sectnum+1 &0377)) {
  413.             sectnum++;
  414.             cblklen = Bytesleft>Blklen ? Blklen:Bytesleft;
  415.             if (putsec(secbuf, cblklen)==ERROR)
  416.                 return ERROR;
  417.             if ((Bytesleft-=cblklen) < 0)
  418.                 Bytesleft = 0;
  419.             sendchar=ACK;
  420.         }
  421.         else if (sectcurr==(sectnum&0377)) {
  422.             zperr( "Received dup Sector");
  423.             sendchar=ACK;
  424.         }
  425.         else if (sectcurr==WCEOT) {
  426.             if (closeit())
  427.                 return ERROR;
  428.             sendline(ACK);
  429.             Lleft=0;    /* Do read next time ... */
  430.             return OK;
  431.         }
  432.         else if (sectcurr==ERROR)
  433.             return ERROR;
  434.         else {
  435.             zperr( "Sync Error");
  436.             return ERROR;
  437.         }
  438.     }
  439. }
  440.  
  441. /*
  442.  * Wcgetsec fetches a Ward Christensen type sector.
  443.  * Returns sector number encountered or ERROR if valid sector not received,
  444.  * or CAN CAN received
  445.  * or WCEOT if eot sector
  446.  * time is timeout for first char, set to 4 seconds thereafter
  447.  ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
  448.  *    (Caller must do that when he is good and ready to get next sector)
  449.  */
  450.  
  451. wcgetsec(rxbuf, maxtime)
  452. char *rxbuf;
  453. int maxtime;
  454. {
  455.     register checksum, wcj, firstch;
  456.     register unsigned short oldcrc;
  457.     register char *p;
  458.     int sectcurr;
  459.  
  460.     for (Lastrx=errors=0; errors<RETRYMAX; errors++) {
  461.  
  462.         if ((firstch=readline(maxtime))==STX) {
  463.             Blklen=1024; goto get2;
  464.         }
  465.         if (firstch==SOH) {
  466.             Blklen=128;
  467. get2:
  468.             sectcurr=readline(1);
  469.             if ((sectcurr+(oldcrc=readline(1)))==0377) {
  470.                 oldcrc=checksum=0;
  471.                 for (p=rxbuf,wcj=Blklen; --wcj>=0; ) {
  472.                     if ((firstch=readline(1)) < 0)
  473.                         goto bilge;
  474.                     oldcrc=updcrc(firstch, oldcrc);
  475.                     checksum += (*p++ = firstch);
  476.                 }
  477.                 if ((firstch=readline(1)) < 0)
  478.                     goto bilge;
  479.                 if (Crcflg) {
  480.                     oldcrc=updcrc(firstch, oldcrc);
  481.                     if ((firstch=readline(1)) < 0)
  482.                         goto bilge;
  483.                     oldcrc=updcrc(firstch, oldcrc);
  484.                     if (oldcrc & 0xFFFF)
  485.                         zperr( "CRC");
  486.                     else {
  487.                         Firstsec=FALSE;
  488.                         return sectcurr;
  489.                     }
  490.                 }
  491.                 else if (((checksum-firstch)&0377)==0) {
  492.                     Firstsec=FALSE;
  493.                     return sectcurr;
  494.                 }
  495.                 else
  496.                     zperr( "Checksum");
  497.             }
  498.             else
  499.                 zperr("Sector number garbled");
  500.         }
  501.         /* make sure eot really is eot and not just mixmash */
  502.         else if (firstch==EOT && Lleft==0)
  503.             return WCEOT;
  504.         else if (firstch==CAN) {
  505.             if (Lastrx==CAN) {
  506.                 zperr( "Sender CANcelled");
  507.                 return ERROR;
  508.             } else {
  509.                 Lastrx=CAN;
  510.                 continue;
  511.             }
  512.         }
  513.         else if (firstch==TIMEOUT) {
  514.             if (Firstsec)
  515.                 goto humbug;
  516. bilge:
  517.             zperr( "TIMEOUT");
  518.         }
  519.         else
  520.             zperr( "Got 0%o sector header", firstch);
  521.  
  522. humbug:
  523.         Lastrx=0;
  524.         while(readline(1)!=TIMEOUT)
  525.             ;
  526.         if (Firstsec) {
  527.             sendline(Crcflg?WANTCRC:NAK);
  528.             Lleft=0;    /* Do read next time ... */
  529.         } else {
  530.             maxtime=40; sendline(NAK);
  531.             Lleft=0;    /* Do read next time ... */
  532.         }
  533.     }
  534.     /* try to stop the bubble machine. */
  535.     canit();
  536.     return ERROR;
  537. }
  538.  
  539.  
  540. /*
  541.  * Process incoming file information header
  542.  */
  543. procheader(name)
  544. char *name;
  545. {
  546.     register char *openmode, *p, **pp;
  547.     static dummy;
  548.     struct stat f;
  549.  
  550.     /* set default parameters and overrides */
  551.     openmode = "w";
  552.     Thisbinary = (!Rxascii) || Rxbinary;
  553.     if (zconv == ZCBIN && Lzconv != ZCRESUM)
  554.         Lzconv = zconv;            /* Remote Binary override */
  555.     if (Lzconv)
  556.         zconv = Lzconv;
  557.     if (Lzmanag)
  558.         zmanag = Lzmanag;
  559.  
  560.     /*
  561.      *  Process ZMODEM remote file management requests
  562.      */
  563.     if (!Rxbinary && zconv == ZCNL)    /* Remote ASCII override */
  564.         Thisbinary = 0;
  565.     if (zconv == ZCBIN)    /* Remote Binary override */
  566.         Thisbinary = TRUE;
  567.     else if (zmanag == ZMAPND)
  568.         openmode = "a";
  569.  
  570.     Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  571.  
  572.     p = name + 1 + strlen(name);
  573.     if (*p) {    /* file coming from Unix or DOS system */
  574.         sscanf(p, "%ld%lo%o%lo%d%ld%d%d",
  575.           &Bytesleft, &Modtime, &Filemode,
  576.           &dummy, &Filesleft, &Totalleft, &dummy, &dummy);
  577.         if (Filemode & UNIXFILE)
  578.             ++Thisbinary;
  579.         if (Verbose) {
  580.             fprintf(stderr,  "Incoming: %s %ld %lo %o\n",
  581.               name, Bytesleft, Modtime, Filemode);
  582.             fprintf(stderr,  "YMODEM header: %s\n", p);
  583.         }
  584.     }
  585.  
  586.  
  587.     else {        /* File coming from CP/M system */
  588.         for (p=name; *p; ++p)        /* change / to _ */
  589.             if ( *p == '/')
  590.                 *p = '_';
  591.  
  592.         if ( *--p == '.')        /* zap trailing period */
  593.             *p = 0;
  594.     }
  595.  
  596.     strcpy(Pathname, name);
  597.     checkpath(name);
  598.  
  599.     if (*name && stat(name, &f)!= -1) {
  600.         zmanag &= ZMMASK;
  601.         vfile("Current %s is %ld %lo", name, f.st_size, f.st_mtime);
  602.         if (Thisbinary && zconv==ZCRESUM) {
  603.             rxbytes = f.st_size & ~511;
  604.             if (Bytesleft < rxbytes) {
  605.                 rxbytes = 0;  goto doopen;
  606.             } else
  607.                 openit(name, "r+");
  608.             if ( !fout)
  609.                 return ZFERR;
  610.             if (fseek(fout, rxbytes, 0)) {
  611.                 closeit();
  612.                 return ZFERR;
  613.             }
  614.             vfile("Crash recovery at %ld", rxbytes);
  615.             return 0;
  616.         }
  617.         else if ((zmanag==ZMNEW) ||
  618.           ((zmanag==ZMNEWL) && Bytesleft <= f.st_size) ) {
  619.             if ((f.st_mtime+1) >= Modtime)
  620.                 goto skipfile;
  621.             goto doopen;
  622.         }
  623.         switch (zmanag & ZMMASK) {
  624.         case ZMCLOB:
  625.         case ZMAPND:
  626.             goto doopen;
  627.         default:
  628.             goto skipfile;
  629.         }
  630.     } else if (zmanag & ZMSKNOLOC) {
  631. skipfile:
  632.         vfile("Skipping %s", name);
  633.         return ZSKIP;
  634.     }
  635. doopen:
  636.     openit(name, openmode);
  637. #ifdef MD
  638.     if ( !fout)
  639.         if (make_dirs(name))
  640.             openit(name, openmode);
  641. #endif
  642.     if ( !fout)
  643.         return ZFERR;
  644.     return 0;
  645. }
  646.  
  647. openit(name, openmode)
  648. char *name, *openmode;
  649. {
  650.     fout = fopen(name, openmode);
  651. }
  652.  
  653. #ifdef MD
  654. /*
  655.  *  Directory-creating routines from Public Domain TAR by John Gilmore
  656.  */
  657.  
  658. /*
  659.  * After a file/link/symlink/dir creation has failed, see if
  660.  * it's because some required directory was not present, and if
  661.  * so, create all required dirs.
  662.  */
  663. make_dirs(pathname)
  664. register char *pathname;
  665. {
  666.     register char *p;        /* Points into path */
  667.     int madeone = 0;        /* Did we do anything yet? */
  668.     int save_errno = errno;        /* Remember caller's errno */
  669.     char *strchr();
  670.  
  671.     if (errno != ENOENT)
  672.         return 0;        /* Not our problem */
  673.  
  674.     for (p = strchr(pathname, '/'); p != NULL; p = strchr(p+1, '/')) {
  675.         /* Avoid mkdir of empty string, if leading or double '/' */
  676.         if (p == pathname || p[-1] == '/')
  677.             continue;
  678.         /* Avoid mkdir where last part of path is '.' */
  679.         if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/'))
  680.             continue;
  681.         *p = 0;                /* Truncate the path there */
  682.         if ( !mkdir(pathname, 0777)) {    /* Try to create it as a dir */
  683.             vfile("Made directory %s\n", pathname);
  684.             madeone++;        /* Remember if we made one */
  685.             *p = '/';
  686.             continue;
  687.         }
  688.         *p = '/';
  689.         if (errno == EEXIST)        /* Directory already exists */
  690.             continue;
  691.         /*
  692.          * Some other error in the mkdir.  We return to the caller.
  693.          */
  694.         break;
  695.     }
  696.     errno = save_errno;        /* Restore caller's errno */
  697.     return madeone;            /* Tell them to retry if we made one */
  698. }
  699.  
  700. #if (MD != 2)
  701. #define    TERM_SIGNAL(status)    ((status) & 0x7F)
  702. #define TERM_COREDUMP(status)    (((status) & 0x80) != 0)
  703. #define TERM_VALUE(status)    ((status) >> 8)
  704. /*
  705.  * Make a directory.  Compatible with the mkdir() system call on 4.2BSD.
  706.  */
  707. mkdir(dpath, dmode)
  708. char *dpath;
  709. int dmode;
  710. {
  711.     int cpid, status;
  712.     struct stat statbuf;
  713.  
  714.     if (stat(dpath,&statbuf) == 0) {
  715.         errno = EEXIST;        /* Stat worked, so it already exists */
  716.         return -1;
  717.     }
  718.  
  719.     /* If stat fails for a reason other than non-existence, return error */
  720.     if (errno != ENOENT) return -1; 
  721.  
  722.     switch (cpid = fork()) {
  723.  
  724.     case -1:            /* Error in fork() */
  725.         return(-1);        /* Errno is set already */
  726.  
  727.     case 0:                /* Child process */
  728.         /*
  729.          * Cheap hack to set mode of new directory.  Since this
  730.          * child process is going away anyway, we zap its umask.
  731.          * FIXME, this won't suffice to set SUID, SGID, etc. on this
  732.          * directory.  Does anybody care?
  733.          */
  734.         status = umask(0);    /* Get current umask */
  735.         status = umask(status | (0777 & ~dmode)); /* Set for mkdir */
  736.         execl("/bin/mkdir", "mkdir", dpath, (char *)0);
  737.         _exit(2);        /* Can't exec /bin/mkdir */
  738.     
  739.     default:            /* Parent process */
  740.         while (cpid != wait(&status)) ;    /* Wait for kid to finish */
  741.     }
  742.  
  743.     if (TERM_SIGNAL(status) != 0 || TERM_VALUE(status) != 0) {
  744.         errno = EIO;        /* We don't know why, but */
  745.         return -1;        /* /bin/mkdir failed */
  746.     }
  747.  
  748.     return 0;
  749. }
  750. #endif /* MD != 2 */
  751. #endif /* MD */
  752.  
  753. /*
  754.  * Putsec writes the n characters of buf to receive file fout.
  755.  *  If not in binary mode, carriage returns, and all characters
  756.  *  starting with CPMEOF are discarded.
  757.  */
  758. putsec(buf, n)
  759. char *buf;
  760. register n;
  761. {
  762.     register char *p;
  763.  
  764.     if (n == 0)
  765.         return OK;
  766.     if (Thisbinary) {
  767.         for (p=buf; --n>=0; )
  768.             putc( *p++, fout);
  769.     }
  770.     else {
  771.         if (Eofseen)
  772.             return OK;
  773.         for (p=buf; --n>=0; ++p ) {
  774.             if ( *p == '\r')
  775.                 continue;
  776.             if (*p == CPMEOF) {
  777.                 Eofseen=TRUE; return OK;
  778.             }
  779.             putc(*p ,fout);
  780.         }
  781.     }
  782.     return OK;
  783. }
  784.  
  785. /*
  786.  * substr(string, token) searches for token in string s
  787.  * returns pointer to token within string if found, NULL otherwise
  788.  */
  789. char *
  790. substr(s, t)
  791. register char *s,*t;
  792. {
  793.     register char *ss,*tt;
  794.     /* search for first char of token */
  795.     for (ss=s; *s; s++)
  796.         if (*s == *t)
  797.             /* compare token with substring */
  798.             for (ss=s,tt=t; ;) {
  799.                 if (*tt == 0)
  800.                     return s;
  801.                 if (*ss++ != *tt++)
  802.                     break;
  803.             }
  804.     return NULL;
  805. }
  806.  
  807. /*
  808.  * Log an error
  809.  */
  810. /*VARARGS1*/
  811. zperr(s,p,u)
  812. char *s, *p, *u;
  813. {
  814.     if (Verbose <= 0)
  815.         return;
  816.     fprintf(stderr, "Retry %d: ", errors);
  817.     fprintf(stderr, s, p, u);
  818.     fprintf(stderr, "\n");
  819. }
  820.  
  821. report(sct)
  822. int sct;
  823. {
  824.     if (Verbose>1)
  825.         fprintf(stderr,"%03d%c",sct,sct%10? ' ' : '\r');
  826. }
  827.  
  828. /*
  829.  * If called as [-][dir/../]vrzCOMMAND set Verbose to 1
  830.  * If called as [-][dir/../]rzCOMMAND set the pipe flag
  831.  * If called as rb use YMODEM protocol
  832.  */
  833. chkinvok(s)
  834. char *s;
  835. {
  836.     register char *p;
  837.  
  838.     p = s;
  839.     while (*p == '-')
  840.         s = ++p;
  841.     while (*p)
  842.         if (*p++ == '/')
  843.             s = p;
  844.     if (*s == 'v') {
  845.         Verbose=1; ++s;
  846.     }
  847.     Progname = s;
  848.     if (s[0]=='r' && s[1]=='z')
  849.         Batch = TRUE;
  850.     if (s[0]=='r' && s[1]=='c')
  851.         Crcflg = TRUE;
  852.     if (s[0]=='r' && s[1]=='b')
  853.         Batch = Nozmodem = TRUE;
  854.     if (s[2] && s[0]=='r' && s[1]=='b')
  855.         Topipe = 1;
  856.     if (s[2] && s[0]=='r' && s[1]=='z')
  857.         Topipe = 1;
  858. }
  859.  
  860. /*
  861.  * Totalitarian Communist pathname processing
  862.  */
  863. checkpath(name)
  864. char *name;
  865. {
  866.     if (Restricted) {
  867.         if (fopen(name, "r") != NULL) {
  868.             canit();
  869.             fprintf(stderr, "\r\nrz: %s exists\n", name);
  870.             bibi(-1);
  871.         }
  872.         /* restrict pathnames to current tree or uucppublic */
  873.         if ( substr(name, "../")
  874.          || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
  875.             canit();
  876.             fprintf(stderr,"\r\nrz:\tSecurity Violation\r\n");
  877.             bibi(-1);
  878.         }
  879.     }
  880. }
  881.  
  882. /*
  883.  * Initialize for Zmodem receive attempt, try to activate Zmodem sender
  884.  *  Handles ZSINIT frame
  885.  *  Return ZFILE if Zmodem filename received, -1 on error,
  886.  *   ZCOMPL if transaction finished,  else 0
  887.  */
  888. tryz()
  889. {
  890.     register c, n;
  891.     register cmdzack1flg;
  892.  
  893.     if (Nozmodem)        /* Check for "rb" program name */
  894.         return 0;
  895.  
  896.  
  897.     for (n=Zmodem?15:5; --n>=0; ) {
  898.         /* Set buffer length (0) and capability flags */
  899. #ifdef SEGMENTS
  900.         stohdr(SEGMENTS*1024L);
  901. #else
  902.         stohdr(0L);
  903. #endif
  904. #ifdef CANBREAK
  905.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK;
  906. #else
  907.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO;
  908. #endif
  909.         if (Zctlesc)
  910.             Txhdr[ZF0] |= TESCCTL;
  911.         Txhdr[ZF0] |= CANRLE;
  912.         Txhdr[ZF1] = CANVHDR;
  913.         /* tryzhdrtype may == ZRINIT */
  914.         zshhdr(4,tryzhdrtype, Txhdr);
  915.         if (tryzhdrtype == ZSKIP)    /* Don't skip too far */
  916.             tryzhdrtype = ZRINIT;    /* CAF 8-21-87 */
  917. again:
  918.         switch (zgethdr(Rxhdr, 0)) {
  919.         case ZRQINIT:
  920.             if (Rxhdr[ZF3] & 0x80)
  921.                 Usevhdrs = 1;    /* we can var header */
  922.             continue;
  923.         case ZEOF:
  924.             continue;
  925.         case TIMEOUT:
  926.             continue;
  927.         case ZFILE:
  928.             zconv = Rxhdr[ZF0];
  929.             zmanag = Rxhdr[ZF1];
  930.             ztrans = Rxhdr[ZF2];
  931.             if (Rxhdr[ZF3] & ZCANVHDR)
  932.                 Usevhdrs = TRUE;
  933.             tryzhdrtype = ZRINIT;
  934.             c = zrdata(secbuf, 1024);
  935.             mode(3);
  936.             if (c == GOTCRCW)
  937.                 return ZFILE;
  938.             zshhdr(4,ZNAK, Txhdr);
  939.             goto again;
  940.         case ZSINIT:
  941.             Zctlesc = TESCCTL & Rxhdr[ZF0];
  942.             if (zrdata(Attn, ZATTNLEN) == GOTCRCW) {
  943.                 stohdr(1L);
  944.                 zshhdr(4,ZACK, Txhdr);
  945.                 goto again;
  946.             }
  947.             zshhdr(4,ZNAK, Txhdr);
  948.             goto again;
  949.         case ZFREECNT:
  950.             stohdr(getfree());
  951.             zshhdr(4,ZACK, Txhdr);
  952.             goto again;
  953.         case ZCOMMAND:
  954.             cmdzack1flg = Rxhdr[ZF0];
  955.             if (zrdata(secbuf, 1024) == GOTCRCW) {
  956.                 if (cmdzack1flg & ZCACK1)
  957.                     stohdr(0L);
  958.                 else
  959.                     stohdr((long)sys2(secbuf));
  960.                 purgeline();    /* dump impatient questions */
  961.                 do {
  962.                     zshhdr(4,ZCOMPL, Txhdr);
  963.                 }
  964.                 while (++errors<20 && zgethdr(Rxhdr,1) != ZFIN);
  965.                 ackbibi();
  966.                 if (cmdzack1flg & ZCACK1)
  967.                     exec2(secbuf);
  968.                 return ZCOMPL;
  969.             }
  970.             zshhdr(4,ZNAK, Txhdr); goto again;
  971.         case ZCOMPL:
  972.             goto again;
  973.         default:
  974.             continue;
  975.         case ZFIN:
  976.             ackbibi(); return ZCOMPL;
  977.         case ZCAN:
  978.             return ERROR;
  979.         }
  980.     }
  981.     return 0;
  982. }
  983.  
  984. /*
  985.  * Receive 1 or more files with ZMODEM protocol
  986.  */
  987. rzfiles()
  988. {
  989.     register c;
  990.  
  991.     for (;;) {
  992.         switch (c = rzfile()) {
  993.         case ZEOF:
  994.         case ZSKIP:
  995.             switch (tryz()) {
  996.             case ZCOMPL:
  997.                 return OK;
  998.             default:
  999.                 return ERROR;
  1000.             case ZFILE:
  1001.                 break;
  1002.             }
  1003.             continue;
  1004.         default:
  1005.             return c;
  1006.         case ERROR:
  1007.             return ERROR;
  1008.         }
  1009.     }
  1010. }
  1011.  
  1012. /*
  1013.  * Receive a file with ZMODEM protocol
  1014.  *  Assumes file name frame is in secbuf
  1015.  */
  1016. rzfile()
  1017. {
  1018.     register c, n;
  1019.  
  1020.     Eofseen=FALSE;
  1021.     n = 20; rxbytes = 0l;
  1022.  
  1023.     if (c = procheader(secbuf)) {
  1024.         return (tryzhdrtype = c);
  1025.     }
  1026.  
  1027.     for (;;) {
  1028. #ifdef SEGMENTS
  1029.         chinseg = 0;
  1030. #endif
  1031.         stohdr(rxbytes);
  1032.         zshhdr(4,ZRPOS, Txhdr);
  1033. nxthdr:
  1034.         switch (c = zgethdr(Rxhdr, 0)) {
  1035.         default:
  1036.             vfile("rzfile: Wrong header %d", c);
  1037.             if ( --n < 0) {
  1038.                 sprintf(endmsg, "rzfile: Wrong header %d", c);
  1039.                 return ERROR;
  1040.             }
  1041.             continue;
  1042.         case ZCAN:
  1043.             sprintf(endmsg, "Sender CANcelled");
  1044.             return ERROR;
  1045.         case ZNAK:
  1046. #ifdef SEGMENTS
  1047.             putsec(secbuf, chinseg);
  1048.             chinseg = 0;
  1049. #endif
  1050.             if ( --n < 0) {
  1051.                 sprintf(endmsg, "rzfile: got ZNAK", c);
  1052.                 return ERROR;
  1053.             }
  1054.             continue;
  1055.         case TIMEOUT:
  1056. #ifdef SEGMENTS
  1057.             putsec(secbuf, chinseg);
  1058.             chinseg = 0;
  1059. #endif
  1060.             if ( --n < 0) {
  1061.                 sprintf(endmsg, "rzfile: TIMEOUT", c);
  1062.                 return ERROR;
  1063.             }
  1064.             continue;
  1065.         case ZFILE:
  1066.             zrdata(secbuf, 1024);
  1067.             continue;
  1068.         case ZEOF:
  1069. #ifdef SEGMENTS
  1070.             putsec(secbuf, chinseg);
  1071.             chinseg = 0;
  1072. #endif
  1073.             if (rclhdr(Rxhdr) != rxbytes) {
  1074.                 /*
  1075.                  * Ignore eof if it's at wrong place - force
  1076.                  *  a timeout because the eof might have gone
  1077.                  *  out before we sent our zrpos.
  1078.                  */
  1079.                 errors = 0;  goto nxthdr;
  1080.             }
  1081.             if (closeit()) {
  1082.                 tryzhdrtype = ZFERR;
  1083.                 vfile("rzfile: closeit returned <> 0");
  1084.                 sprintf(endmsg,"Error closing file");
  1085.                 return ERROR;
  1086.             }
  1087.             vfile("rzfile: normal EOF");
  1088.             return c;
  1089.         case ERROR:    /* Too much garbage in header search error */
  1090. #ifdef SEGMENTS
  1091.             putsec(secbuf, chinseg);
  1092.             chinseg = 0;
  1093. #endif
  1094.             if ( --n < 0) {
  1095.                 sprintf(endmsg, "Persistent CRC or other ERROR");
  1096.                 return ERROR;
  1097.             }
  1098.             zmputs(Attn);
  1099.             continue;
  1100.         case ZSKIP:
  1101. #ifdef SEGMENTS
  1102.             putsec(secbuf, chinseg);
  1103.             chinseg = 0;
  1104. #endif
  1105.             Modtime = 1;
  1106.             closeit();
  1107.             sprintf(endmsg, "Sender SKIPPED file");
  1108.             return c;
  1109.         case ZDATA:
  1110.             if (rclhdr(Rxhdr) != rxbytes) {
  1111.                 if ( --n < 0) {
  1112.                     sprintf(endmsg,"Data has bad addr");
  1113.                     return ERROR;
  1114.                 }
  1115. #ifdef SEGMENTS
  1116.                 putsec(secbuf, chinseg);
  1117.                 chinseg = 0;
  1118. #endif
  1119.                 zmputs(Attn);  continue;
  1120.             }
  1121. moredata:
  1122.             if (Verbose>1)
  1123.                 fprintf(stderr, "\r%7ld ZMODEM%s    ",
  1124.                   rxbytes, Crc32r?" CRC-32":"");
  1125. #ifdef SEGMENTS
  1126.             if (chinseg >= (1024 * SEGMENTS)) {
  1127.                 putsec(secbuf, chinseg);
  1128.                 chinseg = 0;
  1129.             }
  1130.             switch (c = zrdata(secbuf+chinseg, 1024))
  1131. #else
  1132.             switch (c = zrdata(secbuf, 1024))
  1133. #endif
  1134.             {
  1135.             case ZCAN:
  1136. #ifdef SEGMENTS
  1137.                 putsec(secbuf, chinseg);
  1138.                 chinseg = 0;
  1139. #endif
  1140.                 sprintf(endmsg, "Sender CANcelled");
  1141.                 return ERROR;
  1142.             case ERROR:    /* CRC error */
  1143. #ifdef SEGMENTS
  1144.                 putsec(secbuf, chinseg);
  1145.                 chinseg = 0;
  1146. #endif
  1147.                 if ( --n < 0) {
  1148.                     sprintf(endmsg, "Persistent CRC or other ERROR");
  1149.                     return ERROR;
  1150.                 }
  1151.                 zmputs(Attn);
  1152.                 continue;
  1153.             case TIMEOUT:
  1154. #ifdef SEGMENTS
  1155.                 putsec(secbuf, chinseg);
  1156.                 chinseg = 0;
  1157. #endif
  1158.                 if ( --n < 0) {
  1159.                     sprintf(endmsg, "TIMEOUT");
  1160.                     return ERROR;
  1161.                 }
  1162.                 continue;
  1163.             case GOTCRCW:
  1164.                 n = 20;
  1165. #ifdef SEGMENTS
  1166.                 chinseg += Rxcount;
  1167.                 putsec(secbuf, chinseg);
  1168.                 chinseg = 0;
  1169. #else
  1170.                 putsec(secbuf, Rxcount);
  1171. #endif
  1172.                 rxbytes += Rxcount;
  1173.                 stohdr(rxbytes);
  1174.                 zshhdr(4,ZACK, Txhdr);
  1175.                 sendline(XON);
  1176.                 goto nxthdr;
  1177.             case GOTCRCQ:
  1178.                 n = 20;
  1179. #ifdef SEGMENTS
  1180.                 chinseg += Rxcount;
  1181. #else
  1182.                 putsec(secbuf, Rxcount);
  1183. #endif
  1184.                 rxbytes += Rxcount;
  1185.                 stohdr(rxbytes);
  1186.                 zshhdr(4,ZACK, Txhdr);
  1187.                 goto moredata;
  1188.             case GOTCRCG:
  1189.                 n = 20;
  1190. #ifdef SEGMENTS
  1191.                 chinseg += Rxcount;
  1192. #else
  1193.                 putsec(secbuf, Rxcount);
  1194. #endif
  1195.                 rxbytes += Rxcount;
  1196.                 goto moredata;
  1197.             case GOTCRCE:
  1198.                 n = 20;
  1199. #ifdef SEGMENTS
  1200.                 chinseg += Rxcount;
  1201. #else
  1202.                 putsec(secbuf, Rxcount);
  1203. #endif
  1204.                 rxbytes += Rxcount;
  1205.                 goto nxthdr;
  1206.             }
  1207.         }
  1208.     }
  1209. }
  1210.  
  1211.  
  1212. /*
  1213.  * Close the receive dataset, return OK or ERROR
  1214.  */
  1215. closeit()
  1216. {
  1217.     time_t time();
  1218.  
  1219.     if (Topipe) {
  1220.         if (pclose(fout)) {
  1221.             return ERROR;
  1222.         }
  1223.         return OK;
  1224.     }
  1225.     if (fclose(fout)==ERROR) {
  1226.         fprintf(stderr, "file close ERROR\n");
  1227.         return ERROR;
  1228.     }
  1229.     if (Modtime) {
  1230.         timep[0] = time(NULL);
  1231.         timep[1] = Modtime;
  1232.         utime(Pathname, timep);
  1233.     }
  1234.     if ((Filemode&S_IFMT) == S_IFREG)
  1235.         chmod(Pathname, (07777 & Filemode));
  1236.     return OK;
  1237. }
  1238.  
  1239. /*
  1240.  * Ack a ZFIN packet, let byegones be byegones
  1241.  */
  1242. ackbibi()
  1243. {
  1244.     register n;
  1245.  
  1246.     vfile("ackbibi:");
  1247.     Readnum = 1;
  1248.     stohdr(0L);
  1249.     for (n=3; --n>=0; ) {
  1250.         purgeline();
  1251.         zshhdr(4,ZFIN, Txhdr);
  1252.         switch (readline(100)) {
  1253.         case 'O':
  1254.             readline(1);    /* Discard 2nd 'O' */
  1255.             vfile("ackbibi complete");
  1256.             return;
  1257.         case RCDO:
  1258.             return;
  1259.         case TIMEOUT:
  1260.         default:
  1261.             break;
  1262.         }
  1263.     }
  1264. }
  1265.  
  1266.  
  1267. /*
  1268.  * Strip leading ! if present, do shell escape. 
  1269.  */
  1270. sys2(s)
  1271. register char *s;
  1272. {
  1273.     if (*s == '!')
  1274.         ++s;
  1275.     return system(s);
  1276. }
  1277. /*
  1278.  * Strip leading ! if present, do exec.
  1279.  */
  1280. exec2(s)
  1281. register char *s;
  1282. {
  1283.     if (*s == '!')
  1284.         ++s;
  1285.     mode(0);
  1286.     execl("/bin/sh", "sh", "-c", s);
  1287. }
  1288. /* End of rz.c */
  1289.